
#include "stm32f10x.h"
#include <rthw.h>
#include <rtthread.h>
#include "adc.h"

#define TIM1_PULSE_1K  36000

#define CPFb_Port       GPIOA
#define CPFb_Pin        GPIO_Pin_5
#define CPCtrl_Port     GPIOA
#define CPCtrl_Pin      GPIO_Pin_8
#define PL_Vref_Port	GPIOB
#define PL_Vref_Pin		GPIO_Pin_0

#define REGULAR_CHANNEL_NUM     2
static uint16_t regular_dma_buf[REGULAR_CHANNEL_NUM];
static uint16_t regular_ready_buf[REGULAR_CHANNEL_NUM];

#define INJECTED_CHANNEL_NUM    1
static uint16_t injected_buf[INJECTED_CHANNEL_NUM];

/* TIM1 : 1ms, CP control */
static void timer1_init(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_OCInitTypeDef TIM1_OCInitStruct;
    GPIO_InitTypeDef GPIO_InitStruct;

    /* CP Ctrol Pin */
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Pin=(CPCtrl_Pin);
    GPIO_Init(CPCtrl_Port, &GPIO_InitStruct);

    /* TIM Base Init*/
    TIM_InternalClockConfig(TIM1);
    TIM_TimeBaseInitStruct.TIM_Prescaler = 1-1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_CenterAligned3;
    TIM_TimeBaseInitStruct.TIM_Period = TIM1_PULSE_1K -1;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 1-1;
    TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);

    /* OC1 ---- CP output*/
    TIM1_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM1_OCInitStruct.TIM_OutputState =TIM_OutputState_Enable;
    TIM1_OCInitStruct.TIM_OutputNState = 0;
    TIM1_OCInitStruct.TIM_Pulse = 8000;
    TIM1_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM1_OCInitStruct.TIM_OCNPolarity = 0;
    TIM1_OCInitStruct.TIM_OCIdleState = 0;
    TIM1_OCInitStruct.TIM_OCNIdleState = 0;
    TIM_OC1Init(TIM1,&TIM1_OCInitStruct);

    TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);

    /* OC2 ----- Triger ADC1 Regular Channel */
    TIM1_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM1_OCInitStruct.TIM_OutputState =TIM_OutputState_Enable;
    TIM1_OCInitStruct.TIM_Pulse = 20;
    TIM1_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC2Init(TIM1,&TIM1_OCInitStruct);

    TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable);

    TIM_CtrlPWMOutputs(TIM1,ENABLE);

    TIM_Cmd(TIM1,ENABLE);

    /* Set CP 100% */
    TIM_SetCompare1 (TIM1,TIM1_PULSE_1K-1);

}

/* TIM3 100us, trigger ADC1 Injected Channel*/
static void timer3_init(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_OCInitTypeDef         TIM_OCInitStruct;

    TIM_InternalClockConfig(TIM3);

    /* TIM Base Init */
    TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStruct.TIM_Period = 100 * 72 - 1;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 1-1;
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);

    /* OC4 ------ triger ADC Injected Channel  */
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState =TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_OutputNState = 0;
    TIM_OCInitStruct.TIM_Pulse = 3000;
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStruct.TIM_OCNPolarity = 0;
    TIM_OCInitStruct.TIM_OCIdleState = 0;
    TIM_OCInitStruct.TIM_OCNIdleState = 0;
    TIM_OC4Init(TIM3,&TIM_OCInitStruct);

    TIM_Cmd(TIM3,ENABLE);
}



/*
***************************ADC1 Init*********************
    Regular Channel :
    CPFb            ADC_Channel_5           rank1
    TemperSensor    ADC_Channel_TempSensor  rank2

    Injected Channel :
    PL_Vref         ADC_Channel_8           rank1
*********************************************************
*/
static void adc1_init(void)
{
    ADC_InitTypeDef ADC_InitStruct;
    DMA_InitTypeDef DMA_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;
    GPIO_InitTypeDef GPIO_InitStruct;

    /* CP Ctrol Pin */
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Pin=(CPCtrl_Pin);
    GPIO_Init(CPCtrl_Port, &GPIO_InitStruct);

    /* ADC Pins */
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
    GPIO_InitStruct.GPIO_Pin=(CPFb_Pin);
    GPIO_Init(CPFb_Port, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin=(PL_Vref_Pin);
    GPIO_Init(PL_Vref_Port, &GPIO_InitStruct);

    RCC_ADCCLKConfig(RCC_PCLK2_Div8);

    ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStruct.ADC_ScanConvMode = ENABLE;
    ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC2;
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStruct.ADC_NbrOfChannel = REGULAR_CHANNEL_NUM;
    ADC_Init(ADC1,&ADC_InitStruct);

    /* regular channel */
    ADC_RegularChannelConfig(ADC1, ADC_Channel_5,1, ADC_SampleTime_71Cycles5);              //CP_Fb
    ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor,2, ADC_SampleTime_71Cycles5);     //TemperSensor

    /* inject channel */
    ADC_InjectedSequencerLengthConfig(ADC1, 1);
    ADC_InjectedChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_71Cycles5);    //PL_Vref
    ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_T3_CC4);
    ADC_ExternalTrigInjectedConvCmd(ADC1,ENABLE);
    ADC_ClearITPendingBit(ADC1,ADC_IT_JEOC);
    ADC_ITConfig(ADC1,ADC_IT_JEOC,ENABLE);

    ADC_DMACmd(ADC1,ENABLE);
    ADC_ExternalTrigConvCmd(ADC1,ENABLE);
    ADC_TempSensorVrefintCmd(ENABLE);
    ADC_Cmd(ADC1, ENABLE);

    /* self calibration */
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));

    /* Regual Channel DMA config */
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) ((&ADC1->DR));
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) regular_dma_buf;
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStruct.DMA_BufferSize = REGULAR_CHANNEL_NUM;
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable ;
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable ;
    DMA_Init(DMA1_Channel1,(DMA_InitTypeDef*)&DMA_InitStruct);
    DMA_ClearITPendingBit(DMA1_IT_TC1);
    DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);
    DMA_Cmd(DMA1_Channel1,ENABLE);

    /* ADC1 NVIC config */
    NVIC_InitStruct.NVIC_IRQChannel = ADC1_2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    /* DMA1 Channel1 NVIC config */
    NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

void DMA1_Channel1_IRQHandler()
{
    rt_interrupt_enter();
    if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET)
    {
        DMA_ClearITPendingBit(DMA1_IT_TC1);
        rt_base_t level = rt_hw_interrupt_disable();
        rt_memcpy(regular_ready_buf, regular_dma_buf, sizeof(regular_dma_buf));
        rt_hw_interrupt_enable(level);

        /* process regular data */
        // process_regular(regular_ready_buf, REGULAR_CHANNEL_NUM);

    }
    rt_interrupt_leave();
}

void ADC1_2_IRQHandler()
{
    rt_interrupt_enter();

    if(ADC_GetITStatus(ADC1,ADC_IT_JEOC)!=RESET)
    {
        ADC_ClearITPendingBit(ADC1,ADC_IT_JEOC);
        rt_base_t level = rt_hw_interrupt_disable();
        injected_buf[0] = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
        rt_hw_interrupt_enable(level);

        /* process injected data */
        // process_injected(injected_buf, INJECTED_CHANNEL_NUM);
    }
    rt_interrupt_leave();
}

int adc_timer_init(void)
{

    rt_memset(injected_buf, 0, sizeof(injected_buf));
    rt_memset(regular_dma_buf, 0, sizeof(regular_dma_buf));
    rt_memset(regular_ready_buf, 0, sizeof(regular_ready_buf));

    adc1_init();
    timer1_init();
    timer3_init();

    return 0;
}

float adc_get_chip_temp(void)
{
    rt_base_t level = rt_hw_interrupt_disable();
    uint32_t value = regular_ready_buf[1];
    rt_hw_interrupt_enable(level);

    float temperature = (float)value * (3.3f / 4096.f);
	temperature = (1.43f - temperature) / 0.0043f + 25.f;
    return temperature;
}

#if defined RT_USING_FINSH && defined RT_USING_CONSOLE
#include "finsh.h"
long cpu_temp(void)
{
    float temp = adc_get_chip_temp();
    rt_kprintf("cpu temperature: %d 'C\n", (int)temp);
    return 0;
}
MSH_CMD_EXPORT(cpu_temp, show cpu temperature);
#endif

